package com.service.infoEntry.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.service.config.utils.*;
import com.service.infoEntry.dao.*;
import com.service.infoEntry.dto.*;
import com.service.infoEntry.entity.*;
import com.service.infoEntry.service.ProgrammeService;
import com.service.infoEntry.service.TeamService;
import com.service.infoEntry.service.UserInfoService;
import com.service.infoEntry.vo.ProgrammeVo;
import com.service.infoEntry.vo.TeamVo;
import com.service.infoEntry.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.activation.MimetypesFileTypeMap;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.service.infoEntry.constant.Constant.INCR;
import static com.service.config.utils.DateUtils.YYYY_MM_DD_HH_MM_SS;
import static com.service.infoEntry.constant.Constant.*;

/**
 * @author hjl
 */
@Slf4j
@Service
public class ProgrammeServiceImpl implements ProgrammeService {
    @Resource
    private ProgrammeDao programmeDao;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private TeamService teamService;
    @Resource
    private TeamDao teamDao;
    @Resource
    private ContentOfDeleteDao deleteDao;
    @Resource
    private TransactionInfoDao transactionInfoDao;
    @Resource
    private ContentOfUpdateDao updateDao;
    @Resource
    private RedisUtil redisUtil;

    @Value("${spring.fileUrl}")
    String fileUrl;
    @Value("${spring.filePath}")
    String filePath;
    @Value("${spring.modelFilePath}")
    String modelFilePath;

    private final Integer PAGE_SIZE = 10;
    private Integer programmeNO = 1;
    private final String modelProgrammeListFilename="modelProgrammeList.xlsx";

    /**
     * 立项
     * @param programmeInfoDto
     * @param userDto
     */
    @Override
    @Transactional
    public Result setUpProgramme(ProgrammeInfoDto programmeInfoDto, UserDto userDto) {
        TeamVo teamVo = teamService.queryTeamByTeamId(programmeInfoDto.getTeamId());
        if(null==teamVo)
        {
            return Result.failure(TEAM_NOT_EXIST,"无当前团队");
        }
        ProgrammeInfo programmeInfo = ModelMapperUtil.strictMap(programmeInfoDto, ProgrammeInfo.class);
        programmeInfo.setId(IdUtil.getStringId());
        programmeInfo.setUpdateTime(DateUtils.getNowDate());
        programmeInfo.setAddTime(DateUtils.getNowDate());
        programmeInfo.setUserId(userDto.getId());
        if(null != programmeInfoDto.getAccessories() && !"".equals(programmeInfoDto.getAccessories()))
        {
            String accessoryNames = programmeInfoDto.getAccessories();
            programmeInfo.setAccessories(accessoryNames);
        }
        String NO = this.generateProgrammeNO();
        //避免项目编号重复
        programmeInfo.setNum(NO);
        //往项目进展记录表中插入数据
        if(!com.service.config.utils.StringUtils.isEmpty(programmeInfo.getProcess()))
        {
//            StringBuilder process=new StringBuilder(programmeInfo.getProcess());
//            process.append(" ").append(userDto.getUsername()).append(" ").append(DateUtils.parseDateToStr("yyyy-dd-MM hh:mm",new Date()));

            this.persistentProcess(programmeInfo,userDto,programmeInfo.getTeamId());
//            programmeInfo.setProcess(new String(process));
        }
        programmeDao.setUpProgramme(programmeInfo);
        try {
            redisUtil.leftPush(INFO_SET_PROGRAMME,JsonXMLUtils.obj2json(programmeInfo));
        } catch (Exception e) {
            log.error("立项错误："+ JSON.toJSONString(programmeInfo));
        }
        return Result.ok();
    }


    /**
     * 附件上传
     * @param files
     * @return
     */
    @Override
    public String uploadAccessory(MultipartFile[] files)  {
        String accessoryUrl = "";
        List<String> list = new ArrayList<>();
        File file1;

        for (MultipartFile file : files) {
            accessoryUrl = filePath +"/"+ file.getOriginalFilename().replaceAll(" ","");
            try{
                file1 = createFile(accessoryUrl);
                file.transferTo(file1);
                //持久化附件路径
                list.add(file.getOriginalFilename());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return list.toString().substring(1).substring(0, list.toString().length() - 2).replaceAll(" ","");
    }

    /**
     * 附件下载
     * @param accessoryName
     * @param response
     * @throws IOException
     */
    @Override
    public void downloadAccessory(String accessoryName,HttpServletResponse response) throws IOException{
        this.downLoadFile(response,filePath,accessoryName);
    }

    /**
     * 根据项目ID查询项目下所有附件信息
     * @param programmeId
     * @return
     */
    @Override
    public List<Map<String, String>> queryAccessory(String programmeId) {
        List<Map<String,String>> accessoryList = new ArrayList<>();
        String accessoryListStr = programmeDao.queryAccessory(programmeId);
        if(null == accessoryListStr || "".equals(accessoryListStr))
        {
            return accessoryList;
        }
        return analyzeAccessory(accessoryListStr);
    }

    @Override
    public Result deleteAccessory(String programmeId, String accessoryName) {
        //判断该项目下是否有附件
        String accessoryListStr = programmeDao.queryAccessory(programmeId);
        if(null==accessoryListStr || "".equals(accessoryListStr))
        {
            return Result.failure(PROGRAMME_NOT_ACCESSORY,NOT_ATTACHMENTS_UNDER_THE_PROJECT);
        }
        //生成List集合
        String[] accessories = accessoryListStr.split(",");
        List<String> accessoriesList = Arrays.asList(accessories);
        List list = new ArrayList(accessoriesList);

        //从list中移除
        boolean flag = true;
        for(int i=0;i<accessories.length;i++)
        {
            if(accessories[i].equals(accessoryName))
            {
                flag = false;
                list.remove(accessoryName);
                break;
            }
        }
        if(flag)
        {
            return Result.failure(ACCESSORY_NOT_EXIST,"该项目下没有该附件");
        }
        //在本地路径下将文件删除
        FileUtils.deleteFile(filePath+accessoryName);
        //（如:a.docx,b.docx）
        String s = list.toString().substring(1).substring(0, list.toString().length() - 2).replaceAll(" ","");
        programmeDao.updateAccessory(programmeId,s);
        return Result.ok();
    }

    @Override
    public ProgrammeInfo queryProgrammeById(String programmeId,String userId,String teamId) {
        ProgrammeInfo programmeInfo = programmeDao.queryProgrammeById(programmeId);
        if (null==programmeInfo)
        {
            //从删除表中查
            List<ContentOfDeleteInfo> contentOfDeleteInfos = deleteDao.queryDeletedContent(teamId, userId, "1", "");
            if(null!=contentOfDeleteInfos && contentOfDeleteInfos.size()>0)
            {
                for (ContentOfDeleteInfo contentOfDeleteInfo : contentOfDeleteInfos) {
                    try {
                        ProgrammeInfo programmeInfo1 = JsonXMLUtils.json2obj(contentOfDeleteInfo.getContent(), ProgrammeInfo.class);
                        if(programmeInfo1.getId().equals(programmeId))
                        {
                            programmeInfo=ModelMapperUtil.strictMap(programmeInfo1,ProgrammeInfo.class);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return programmeInfo;
            }
        }
        return programmeInfo;
    }
    /**
     * 上传文件
     * @param s
     * @return
     */
    private File createFile(String s) {
        File file = new File(s);
        return file;
    }

    /**
     * 自动生成项目编号 20200101001
     */
    private String generateProgrammeNO()
    {
        //20200101010101
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String today =  simpleDateFormat.format(date);
        StringBuilder stringBuilder = new StringBuilder();
        try {
            long incr = redisUtil.incr(INCR, 1);
            //20200101001
            stringBuilder.append("P").append(today).append(StringUtils.leftPad(String.valueOf(incr), 3, '0'));
            return stringBuilder.toString();
        }catch (Exception e) {
            //20200101001
            stringBuilder.append("P").append(today).append(StringUtils.leftPad(String.valueOf(programmeNO), 3, '0'));
            return stringBuilder.toString();
        }

    }

    @Override
    public Result updateProgrammeInfo(ProgrammeInfoDto programmeInfoDto, UserDto userDto) {
        ProgrammeInfo programmeInfo = programmeDao.queryProgrammeByNo(programmeInfoDto.getNum());
        if(null == programmeInfo)
        {
            return Result.failure(PROGRAMME_NOT_EXIST,PROJECT_DOES_NOT_EXIST);
        }
        if(programmeInfo.getUserId().equals(userDto.getId()))
        {
            ProgrammeInfo programmeInfo1 = ModelMapperUtil.strictMap(programmeInfoDto, ProgrammeInfo.class);
            programmeInfo1.setUpdateTime(DateUtils.getNowDate());
            programmeInfo1.setAccessories(programmeInfoDto.getAccessories());
            //将数据库查询到的附件和新上传的附件进行对比，添加->去重->持久化
            String s = programmeDao.queryAccessory(programmeInfo.getId());
            List list2;
            List list3;
            String s1;
            String s2;
            if(null != s && !"".equals(s))
            {
                list2 = new ArrayList(Arrays.asList(s.split(",")));
                list3 = new ArrayList(Arrays.asList(programmeInfoDto.getAccessories().split(",")));
                list2.addAll(list3);
                s1 = list2.stream().distinct().collect(Collectors.toList()).toString();
                s2 = s1.substring(1).substring(0, s1.length() - 2).replaceAll(" ","");
                programmeInfo1.setAccessories(s2);
            }

            //往项目进展记录表中插入数据
            if(null != programmeInfo1.getProcess() && !"".equals(programmeInfo1.getProcess()))
            {
                this.persistentProcess(programmeInfo1,userDto,programmeInfo1.getTeamId());
            }

            programmeDao.updateProgrammeInfo(programmeInfo1);
            return Result.ok();
        }
        return Result.failure(USER_NO_AUTHORITY, INSUFFICIENT_USER_PERMISSIONS);
    }

    /**
     * 持久化项目进展
     */
    public void persistentProcess(ProgrammeInfo programmeInfo,UserDto userDto,String teamId)
    {
        if (null != programmeInfo.getProcess() && !"".equals(programmeInfo.getProcess()))
        {
            ContentOfUpdateInfo updateInfo=new ContentOfUpdateInfo();
            updateInfo.setId(IdUtil.getStringId());
            updateInfo.setTeamId(teamId);
            updateInfo.setContent(programmeInfo.getProcess());
            updateInfo.setContentNo(programmeInfo.getNum());
            updateInfo.setContentName(programmeInfo.getName());
            updateInfo.setStatus(programmeInfo.getStatus().toString());
            updateInfo.setContentType("1");
            updateInfo.setUserId(userDto.getId());
            updateInfo.setUsername(userDto.getUsername());
            updateInfo.setFullName(userDto.getFullName());
            updateInfo.setUpdateTime(DateUtils.getNowDate());
            updateDao.addUpdateContent(updateInfo);
        }
    }

    @Override
    public Result closeProgramme(ProgrammeInfoDto programmeInfoDto, String userId) {
        //项目编号
        String programmeNO = programmeInfoDto.getNum();
        ProgrammeInfo programmeInfo = programmeDao.queryProgrammeByNo(programmeNO);
        /**
         * 项目信息为空，不能关闭
         */
        if(com.service.config.utils.StringUtils.isNull(programmeInfo))
        {
            return Result.failure(PROGRAMME_NOT_EXIST,programmeNO);
        }
        if(programmeInfo.getUserId().equals(userId))
        {
            programmeInfo.setCloseTime(DateUtils.getNowDate());
            programmeInfo.setUpdateTime(DateUtils.getNowDate());
            programmeInfo.setStatus(4);
            programmeInfo.setCloseReason(programmeInfoDto.getCloseReason());
            programmeDao.updateProgrammeInfo(programmeInfo);
            return Result.ok();
        }
        return Result.failure(USER_NO_AUTHORITY, INSUFFICIENT_USER_PERMISSIONS);
    }

    @Override
    public ProgrammeVo queryProgrammeOfTeamById(String programmeNo,String userId,String teamId) {
        ProgrammeVo programmeVo = new ProgrammeVo();
        ProgrammeInfo programmeInfo = programmeDao.queryProgrammeOfTeamByNo(programmeNo);
        boolean flag = false;
        /**
         * 如果项目信息表中没有该数据，则去删除表中查询
         */
        if (com.service.config.utils.StringUtils.isNull(programmeInfo))
        {
            //从删除表中查
            List<ContentOfDeleteInfo> contentOfDeleteInfos = deleteDao.queryDeletedContent(teamId, userId, "1", "");
            for (ContentOfDeleteInfo contentOfDeleteInfo : contentOfDeleteInfos) {
                try {
                    ProgrammeInfo programmeInfo1 = JsonXMLUtils.json2obj(contentOfDeleteInfo.getContent(), ProgrammeInfo.class);
                    if (com.service.config.utils.StringUtils.isNotNull(programmeInfo1)) {
                        if (com.service.config.utils.StringUtils.isNotEmpty(programmeInfo1.getNum())) {
                            if(programmeInfo1.getNum().equals(programmeNo))
                            {
                                programmeInfo=programmeInfo1;
                                flag=true;
                                break;
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        if(programmeInfo != null)
        {
//            BeanUtils.copyProperties(programmeInfo,programmeVo);
            programmeVo = ModelMapperUtil.strictMap(programmeInfo,ProgrammeVo.class);
            programmeVo.setDeleted(flag);
            if(null != programmeInfo.getAccessories())
            {
                List<Map<String, String>> list1 = analyzeAccessory(programmeInfo.getAccessories());
                programmeVo.setAccessories(list1);
            }
            UserVo userVo = userInfoService.queryByUserId(programmeInfo.getUserId());
            if(null != userVo)
            {
                if(null!= userVo.getId() && !"".equals(userVo.getId()) && userId.equals(userVo.getId()))
                {
                    userVo.setCurrentUser(true);
                }
                if (userVo.getFullName() == null) {
                    userVo.setFullName("");
                }
                programmeVo.setUserVo(userVo);
            }
            return programmeVo;
        }
        return null;
    }

    /**
     * 格式化附件名称
     * @param accessoryListStr
     * @return
     */
    public List<Map<String,String>> analyzeAccessory(String accessoryListStr)
    {
        Map<String,String> accessoryMap;
        List<Map<String,String>> accessoryList = new ArrayList<>();
        if(accessoryListStr == null || "".equals(accessoryListStr))
        {
            return accessoryList;
        }
        String[] accessories = accessoryListStr.split(",");
        for(int i = 0;i < accessories.length;i++)
        {
            accessoryMap = new HashMap<>(16);
            accessoryMap.put("name",accessories[i]);
            accessoryMap.put("url",fileUrl + accessories[i]);
            accessoryList.add(accessoryMap);
        }
        return accessoryList;
    }

    /**
     * 导出项目清单
     * @param teamId
     * @param userId
     * @return
     */
    @Override
    public Result exportProgrammeList(String teamId,String userId) {
        //当前用户的当前团队下的所有公开项目和自己的所有项目
        List<ProgrammeInfo> programmeInfos = programmeDao.queryProgrammesByTeamId(teamId,userId);
        if(null == programmeInfos || programmeInfos.size()<=0)
        {
            return Result.failure(PROGRAMME_NOT_EXIST,NOT_ATTACHMENTS_UNDER_THE_PROJECT);
        }
        //团队下所有用户
        List<UserInfo> userInfos = teamDao.queryAllUserInTeam(teamId);
        if(null == userInfos || userInfos.size()<=0)
        {
            return Result.failure(TEAM_NO_USER,NOT_USER_UNDER_TEAM);
        }
        //当前团队信息
        TeamVo teamVo = teamService.queryTeamByTeamId(teamId);
        if(null == teamVo)
        {
            return Result.failure(TEAM_NOT_EXIST,TEAM_DOES_NOT_EXIST);
        }
        List<ExportProgrammeInfoDto> exportProgrammes = new ArrayList<>();
        ExportProgrammeInfoDto exportProgramme;

        List<ContentOfUpdateInfo> processContentList = updateDao.queryUpdateContent(teamId, userId, "1", "", "");
        //排序
        processContentList=processContentList.stream().sorted(Comparator.comparing(ContentOfUpdateInfo::getUpdateTime).reversed()).collect(Collectors.toList());

        List<String> processList;
        String processStr="";
        StringBuilder process = new StringBuilder();
        for (ProgrammeInfo programmeInfo : programmeInfos) {
            exportProgramme = ModelMapperUtil.strictMap(programmeInfo, ExportProgrammeInfoDto.class);

            processList=new ArrayList<>();
            for (ContentOfUpdateInfo updateInfo : processContentList) {
                if(updateInfo.getContentNo().equals(programmeInfo.getNum()))
                {
                    if(com.service.config.utils.StringUtils.isEmpty(updateInfo.getFullName()))
                    {
                        processStr = DateUtils.parseDateToStr(YYYY_MM_DD_HH_MM_SS,updateInfo.getUpdateTime()) + " " + updateInfo.getUsername()+ " " +updateInfo.getContent() ;
                    }else {
                        processStr = DateUtils.parseDateToStr(YYYY_MM_DD_HH_MM_SS,updateInfo.getUpdateTime()) + " " + updateInfo.getUsername()+" "+updateInfo.getFullName()+ " " +updateInfo.getContent() ;
                    }
                    processList.add(processStr);
                }
            }
            for (String s : processList) {
                process.append(s).append("\n");
            }
            exportProgramme.setProcess(process.toString());

            exportProgramme.setTeamName(teamVo.getTeamName());
            for (UserInfo userInfo : userInfos) {
                if(userInfo.getId().equals(programmeInfo.getUserId()))
                {
                    if (userInfo.getFullName() == null) {
                        exportProgramme.setUsername(userInfo.getUsername()+"");
                    }else {
                        exportProgramme.setUsername(userInfo.getUsername()+userInfo.getFullName());
                    }
                }
            }
            exportProgrammes.add(exportProgramme);
        }

        String currentTime = Long.toString(System.currentTimeMillis());
        EasyExcel.write(filePath+"项目清单_"+currentTime+".xlsx", ExportProgrammeInfoDto.class).sheet().doWrite(exportProgrammes);
        return Result.ok().setData(fileUrl+"项目清单_"+currentTime+".xlsx");
    }

    /**
     * 查询当前团队中的所有项目
     * @param teamId
     * @return
     */
    @Override
    public List<ProgrammeVo> queryAllProgrammeInTeam(String teamId,String userId) {
        List<ProgrammeVo> programmeVoList = new ArrayList<>();
        ProgrammeVo programmeVo = null;
        UserVo userVo;
        List<ProgrammeInfo> programmeInfos = teamDao.queryAllProgrammeInTeam(teamId);
        if(null != programmeInfos && programmeInfos.size() > 0)
        {
            for (ProgrammeInfo programmeInfo : programmeInfos) {
                programmeVo = ModelMapperUtil.strictMap(programmeInfo,ProgrammeVo.class);
                userVo = userInfoService.queryByUserId(programmeInfo.getUserId());
                if(programmeInfo.getUserId().equals(userId))
                {
                    userVo.setCurrentUser(true);
                }
                programmeVo.setUserVo(userVo);
                programmeVoList.add(programmeVo);
            }
            programmeVoList.forEach(programmeVo1 -> {
                if (programmeVo1.getUserVo().getFullName() == null) {
                    programmeVo1.getUserVo().setFullName("");
                }
            });
            return programmeVoList;
        }
        return Collections.EMPTY_LIST;
    }

    @Override
    public Map<String, Object> queryProgramme(String teamId, String userId, String name, Integer status, Integer programmeStatus, Integer page) {
        Map<String,Object> map = new HashMap<>(16);
        StringBuilder stringBuilder = new StringBuilder();
        if(name != null)
        {
            name = stringBuilder.append("%").append(name).append("%").toString();
        }
        PageHelper.startPage(page,PAGE_SIZE,"add_time DESC");
        List<ProgrammeInfo> programmeInfos = programmeDao.queryProgramme(teamId,userId,name,status,programmeStatus);
        PageInfo<ProgrammeInfo> pageInfo = new PageInfo<ProgrammeInfo>(programmeInfos);
        ProgrammeVo programmeVo;
        List<ProgrammeVo> programmeVos = new ArrayList<>();
        UserVo userVo;
        List<Map<String,String>> accessories;
        for (ProgrammeInfo programmeInfo : programmeInfos) {
            programmeVo = new ProgrammeVo();
            BeanUtils.copyProperties(programmeInfo,programmeVo);
            accessories = analyzeAccessory(programmeInfo.getAccessories());
            userVo = userInfoService.queryByUserId(programmeInfo.getUserId());
            if(null != userVo)
            {
                if(userVo.getId().equals(userId))
                {
                    userVo.setCurrentUser(true);
                }
                programmeVo.setUserVo(userVo);
            }
            programmeVo.setAccessories(accessories);

            programmeVos.add(programmeVo);
        }
        programmeVos.forEach(programmeVo1 -> {
            if (programmeVo1.getUserVo()!=null && programmeVo1.getUserVo().getFullName() == null) {
                programmeVo1.getUserVo().setFullName("");
            }
        });

        programmeVos=programmeVos.stream().sorted(Comparator.comparing(ProgrammeVo::getAddTime).reversed()).collect(Collectors.toList());

        map.put("programmes",programmeVos);
        map.put("pageSize",PAGE_SIZE);
        map.put("pageIndex",page);
        map.put("totalRecords",pageInfo.getTotal());
        map.put("totalPages",pageInfo.getPages());
        return map;
    }

    @Override
    public ProgrammeVo queryProgrammeByNo(String programmeId) {
        ProgrammeInfo programmeInfo = programmeDao.queryProgrammeByNo(programmeId);
        ProgrammeVo programmeVo=null;
        if(null != programmeInfo)
        {
            programmeVo = ModelMapperUtil.strictMap(programmeInfo, ProgrammeVo.class);
        }
        return programmeVo;
    }

    @Override
    public List<ProgrammeInfo> queryAllByDate(ProgrammeInfo programmeInfo) {
        return programmeDao.queryAllByDate();
    }

    @Override
    public void downloadModelProgrammeList(HttpServletResponse response) throws IOException {
        this.downLoadFile(response,modelFilePath,modelProgrammeListFilename);
    }

    /**
     * 下载文件代码抽取
     * @param response
     * @param filePath
     * @param fileName
     */
    public void downLoadFile(HttpServletResponse response,String filePath,String fileName)
    {
        String fileUrl = filePath + fileName;

        String type = new MimetypesFileTypeMap().getContentType(fileName);
        //设置content type  告诉客户端所发送的数据属于什么类型
        response.setHeader("Content-type",type);
        try {
            //设置编码
            String code = new String(fileName.getBytes("utf-8"),"iso-8859-1");
            //设置扩展头，当content-type的类型为要下载的类型时，这个信息头会告诉浏览器这个文件的名字和类型。
            response.setHeader("Content-Disposition", "attachment;filename=" + code);
            // 发送给客户端的数据
            OutputStream outputStream = response.getOutputStream();
            byte[] buff = new byte[1024];
            BufferedInputStream bis = null;
            // 读取filename
            bis = new BufferedInputStream(new FileInputStream(new File(fileUrl)));
            int i = bis.read(buff);
            while (i != -1) {
                outputStream.write(buff, 0, buff.length);
                outputStream.flush();
                i = bis.read(buff);
            }
        }catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public Result uploadProgrammeList(MultipartFile file, String teamId, UserDto userDto) throws Exception {
        ProgrammeInfo programmeInfo;
        boolean flag;
        UserInfo userInfo;

        // 1.判断文件是否为空
        if (file == null) {
            return Result.failure(UPLOAD_EXCEL_EMPTY, UPLOAD_EXCEL_EMPTY_INFO);
        }
        // 2.判断上传内容是否符合要求
        String fileName = file.getOriginalFilename();
        // 判断是否是excel文件
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            return Result.failure(UPLOAD_EXCEL_ERROR, UPLOAD_EXCEL_ERROR_INFO);
        }
        //获取Excel表格数据
        List<UploadProgrammeDto> uploadProgrammeDtoList = this.batchImport(file,UploadProgrammeDto.class,2);
        if(null==uploadProgrammeDtoList)
        {
            return Result.failure(FILE_ISNULL,"当前文件无数据");
        }
        //校验Excel数据
        Map<Integer, String> result = checkExcelData(uploadProgrammeDtoList);

        //数据有异常,返回错误信息
        if(result.containsKey(0))
        {
            return Result.failure(DATA_FORMAT_WRONG,result.get(0));
        }
        //当前团队下所有项目
        List<ProgrammeInfo> programmeInfos = programmeDao.queryAllProgrammeInTeam(teamId);

        for (UploadProgrammeDto uploadProgrammeDto : uploadProgrammeDtoList) {
            if(null!=uploadProgrammeDto)
            {
                flag=true;
                for (ProgrammeInfo programmeInfo1 : programmeInfos) {
                    //项目唯一标识:项目名称+项目描述+行业+区域，且只能修改自己的项目，如果完全一致，则修改该项目，否则新创建一个项目
                    if(uploadProgrammeDto.getName().equals(programmeInfo1.getName())
                            && uploadProgrammeDto.getBusiness().equals(programmeInfo1.getBusiness())
                            && uploadProgrammeDto.getRegion().equals(programmeInfo1.getRegion())
                            && programmeInfo1.getUserId().equals(userDto.getId())
                    ){
                        //数据库中有当前项目，则修改
                        programmeInfo = ModelMapperUtil.strictMap(uploadProgrammeDto, ProgrammeInfo.class);
                        programmeInfo.setId(programmeInfo1.getId());
                        programmeInfo.setNum(programmeInfo1.getNum());
                        programmeInfo.setStatus(parseProgrammeStatus1(uploadProgrammeDto.getStatusStr()));
                        programmeInfo.setTrackStatus(parseTrackStatusStr(uploadProgrammeDto.getTrackStatusStr()));
                        programmeInfo.setUpdateTime(DateUtils.getNowDate());
                        programmeInfo.setIsTop(isTop(uploadProgrammeDto.getIsTopStr()));
                        programmeInfo.setProPower(uploadProgrammeDto.getProPower().concat("%"));
                        programmeInfo.setCloseReason("");
                        if(null!=programmeInfo.getStatus() && programmeInfo.getStatus()==4)
                        {
                            programmeInfo.setCloseTime(DateUtils.getNowDate());
                        }
                        //往项目进展记录表中插入数据
                        if(null != programmeInfo.getProcess() && !"".equals(programmeInfo.getProcess()))
                        {
                            this.persistentProcess(programmeInfo,userDto,programmeInfo.getTeamId());
                        }
                        programmeDao.updateProgrammeInfo(programmeInfo);

                        flag=false;
                        break;
                    }
                }
                if(flag)
                {
                    //数据库没有当前项目，则插入
                    programmeInfo = ModelMapperUtil.strictMap(uploadProgrammeDto, ProgrammeInfo.class);

                    programmeInfo.setUserId(userDto.getId());
                    programmeInfo.setId(IdUtil.getStringId());
                    programmeInfo.setNum(generateProgrammeNO());
                    programmeInfo.setTeamId(teamId);
                    programmeInfo.setStatus(parseProgrammeStatus1(uploadProgrammeDto.getStatusStr()));
                    programmeInfo.setTrackStatus(parseTrackStatusStr(uploadProgrammeDto.getTrackStatusStr()));
                    programmeInfo.setAddTime(DateUtils.getNowDate());
                    programmeInfo.setUpdateTime(DateUtils.getNowDate());
                    programmeInfo.setIsTop(isTop(uploadProgrammeDto.getIsTopStr()));

                    double v = Double.parseDouble(uploadProgrammeDto.getProPower());
                    DecimalFormat df = new DecimalFormat("0.00%");
                    String r = df.format(v);
                    programmeInfo.setProPower(r);
                    programmeInfo.setCloseReason("");
                    if(null!=programmeInfo.getStatus() && programmeInfo.getStatus()==4)
                    {
                        programmeInfo.setCloseTime(DateUtils.getNowDate());
                    }
                    //往项目进展记录表中插入数据
                    if(null != programmeInfo.getProcess() && !"".equals(programmeInfo.getProcess()))
                    {
                        this.persistentProcess(programmeInfo,userDto,programmeInfo.getTeamId());
                    }
                    programmeDao.setUpProgramme(programmeInfo);
                }
            }
        }
        return Result.ok();
    }

    @Override
    public Result deleteProgrammeOrTransaction(String teamId, String no, String type,UserDto userDto) {
        TeamInfo teamInfo = teamDao.queryTeamByTeamId(teamId);
        if(null == teamInfo)
        {
            return Result.failure(TEAM_NOT_EXIST,TEAM_DOES_NOT_EXIST);
        }
        if (type.equals("1"))
        {
            //项目
            ProgrammeInfo programmeInfo = programmeDao.queryProgrammeByNo(no);
            if(null == programmeInfo)
            {
                return Result.failure(PROGRAMME_NOT_EXIST,PROJECT_DOES_NOT_EXIST);
            }
            //只有自己创建的项目才可删除
            if(programmeInfo.getUserId().equals(userDto.getId()))
            {
                int i=programmeDao.deleteProgramme(no);

                try {
                    ContentOfDeleteInfo contentOfDelete=new ContentOfDeleteInfo();
                    contentOfDelete.setId(IdUtil.getStringId());
                    contentOfDelete.setTeamId(teamId);
                    contentOfDelete.setContent(JsonXMLUtils.obj2json(programmeInfo));
                    contentOfDelete.setContentName(programmeInfo.getName());
                    contentOfDelete.setStatus(programmeInfo.getProgrammeStatus());
                    contentOfDelete.setContentType("1");
                    contentOfDelete.setUserId(userDto.getId());
                    contentOfDelete.setUsername(userDto.getUsername());
                    contentOfDelete.setFullName(userDto.getFullName());
                    contentOfDelete.setDeleteTime(DateUtils.getNowDate());
                    deleteDao.addDeletedContent(contentOfDelete);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return Result.ok();
            }else {
                return Result.failure(USER_NO_AUTHORITY,INSUFFICIENT_USER_PERMISSIONS);
            }

        }else if(type.equals("0"))
        {
            //事务
            TransactionInfo transactionInfo = transactionInfoDao.searchTransactionByNo(no);
            if(null == transactionInfo)
            {
                return Result.failure(TRANSACTION_NOT_EXIST,TRANSACTION_DOES_NOT_EXIST);
            }
            //只有自己创建的事务才可删除
            if(transactionInfo.getUserId().equals(userDto.getId()))
            {
                int i = transactionInfoDao.deleteTransaction(no);

                try {
                    ContentOfDeleteInfo contentOfDelete=new ContentOfDeleteInfo();
                    contentOfDelete.setId(IdUtil.getStringId());
                    contentOfDelete.setTeamId(teamId);
                    contentOfDelete.setContent(JsonXMLUtils.obj2json(transactionInfo));
                    contentOfDelete.setContentName(transactionInfo.getDesc());
                    contentOfDelete.setStatus(transactionInfo.getTransactionStatus());
                    contentOfDelete.setContentType("0");
                    contentOfDelete.setUserId(userDto.getId());
                    contentOfDelete.setUsername(userDto.getUsername());
                    contentOfDelete.setFullName(userDto.getFullName());
                    contentOfDelete.setDeleteTime(DateUtils.getNowDate());
                    deleteDao.addDeletedContent(contentOfDelete);
                } catch (Exception e) {
                    log.error(e.getMessage());
                    log.error("deleteError:"+teamId+":"+no+":"+type+":"+userDto);
                }
                return Result.ok();
            }else {
                return Result.failure(USER_NO_AUTHORITY,INSUFFICIENT_USER_PERMISSIONS);
            }
        }
        return Result.failure(DATA_IS_WRONG,DATA_ERROR);
    }

    @Override
    public Map<String,Object> queryDeletedProgrammeOrTransaction(String teamId, String userId,String type,Integer page,String name) throws Exception {
        Map<String,Object> map = new HashMap<>(16);
        if(name!=null && !"".equals(name))
        {
            name="%"+name+"%";
        }
        PageHelper.startPage(page,PAGE_SIZE,"delete_time DESC");
        List<ContentOfDeleteInfo> deleteInfoList = deleteDao.queryDeletedContent(teamId,userId,type,name);
        PageInfo<ProgrammeInfo> pageInfo = new PageInfo(deleteInfoList);
        List<ContentOfDeleteDto> deleteDtoDatas=new ArrayList<>();

        for (ContentOfDeleteInfo deleteData : deleteInfoList) {
            ContentOfDeleteDto contentOfDeleteDto = ModelMapperUtil.strictMap(deleteData, ContentOfDeleteDto.class);
            if(type.equals("1"))
            {
                contentOfDeleteDto.setContent(JsonXMLUtils.json2obj(deleteData.getContent(),ProgrammeInfo.class));
            }else if(type.equals("0"))
            {
                contentOfDeleteDto.setContent(JsonXMLUtils.json2obj(deleteData.getContent(),TransactionInfo.class));
            }
            deleteDtoDatas.add(contentOfDeleteDto);
        }

        deleteDtoDatas=deleteDtoDatas.stream().sorted(Comparator.comparing(ContentOfDeleteDto::getDeleteTime).reversed()).collect(Collectors.toList());
        map.put("deletedData",deleteDtoDatas);
        map.put("pageSize",PAGE_SIZE);
        map.put("pageIndex",page);
        map.put("totalRecords",pageInfo.getTotal());
        map.put("totalPages",pageInfo.getPages());

        return map;
    }

    @Override
    public List<ContentOfUpdateInfo> queryUpdateProcess(String teamId, String userId,String programmeNo) {
        List<ContentOfUpdateInfo> contentOfUpdateInfos = updateDao.queryUpdateContent(teamId, userId, "1", "", programmeNo);
        contentOfUpdateInfos = contentOfUpdateInfos.stream().sorted(Comparator.comparing(ContentOfUpdateInfo::getUpdateTime).reversed()).collect(Collectors.toList());
        return contentOfUpdateInfos;
    }

    public <T> List<T> batchImport(MultipartFile file,Class<T> t,int startLine) throws Exception {
        /*
         * 判断文件名的合法性
         * 判断文件是2003版or2007版
         */
        String fileName = file.getOriginalFilename();
        String[] fullName = null;
        if (fileName != null) {
            fullName = fileName.split("\\.");
        }
        //log.info(fullName[1]);
        boolean isExcel2003 = true;
        if (fullName != null) {
            String suffix = fullName[1];
            if (!suffix.equals("xls") && !suffix.equals("xlsx")) {
                throw new Exception("上传不正确");
            }
            if (suffix.equals("xlsx")) {
                isExcel2003 = false;
            }
        }
        InputStream iStream = file.getInputStream(); //IO流
        Workbook workbook = null; //创建工作簿
        try {
            if (isExcel2003) {
                workbook = new HSSFWorkbook(iStream); //2003版
            } else {
                workbook = new XSSFWorkbook(iStream); //2007版
            }
        }catch (Exception e)
        {
            return null;
        }
        //将文件存储到本地
        String savePath = null;
        try {
            savePath = filePath + fileName;
            log.info(savePath);
            OutputStream os = new FileOutputStream(savePath); // 保存到当前路径savePath
            workbook.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            log.error("File saving error !");
            e.printStackTrace();
        }
        Workbook workbook2 = WorkbookFactory.create(file.getInputStream());
        Sheet sheet = workbook2.getSheetAt(0);
        ExcelUtil<T> util = new ExcelUtil<>(t);
        List<T> uploadProgrammeDtoList = util.importExcel(sheet.getSheetName(), workbook2, startLine);
        return uploadProgrammeDtoList;
    }

    public Map<Integer,String> checkExcelData(List<UploadProgrammeDto> uploadProgrammeDtoList)
    {
        Map<Integer,String> result=new HashMap<>();
        for (int i=0;i<uploadProgrammeDtoList.size();i++)
        {
            if(null!=uploadProgrammeDtoList.get(i))
            {
                if (null==uploadProgrammeDtoList.get(i).getName()||"".equals(uploadProgrammeDtoList.get(i).getName()))
                {
                    result.put(0,"第"+(i+1)+"个项目的项目名称输入不能为空");
                    return result;
                }

                if(null==uploadProgrammeDtoList.get(i).getStatusStr()|| "".equals(uploadProgrammeDtoList.get(i).getStatusStr()) )
                {
                    result.put(0,"第"+(i+1)+"个项目的项目状态为空");
                    return result;
                }else if(null==parseProgrammeStatus1(uploadProgrammeDtoList.get(i).getStatusStr()))
                {
                    result.put(0,"第"+(i+1)+"个项目的项目状态填写不合法");
                    return result;
                }
                if (null==uploadProgrammeDtoList.get(i).getRegion()||"".equals(uploadProgrammeDtoList.get(i).getRegion()))
                {
                    result.put(0,"第"+(i+1)+"个项目的区域输入不能为空");
                    return result;
                }
                if (null==uploadProgrammeDtoList.get(i).getBusiness()||"".equals(uploadProgrammeDtoList.get(i).getBusiness()))
                {
                    result.put(0,"第"+(i+1)+"个项目的行业输入不能为空");
                    return result;
                }
            }
        }

        result.put(1,"");
        return result;
    }

    /**
     * 解析项目状态:0-启动;1-下单;2-交付;3-运维;4-关闭
     * 0--启动 1--POC试用 2--形成PO 3--交付验收 4--形成收入 5--持续运维 1-1--挂起（11试用未转商用）1-2--丢标（12异常关闭）
     * @param status
     * @return
     */
    public Integer parseProgrammeStatus1(String status)
    {
        switch (status)
        {
            case "启动":
                return 0;
            case "POC试用":
                return 1;
            case "形成PO":
                return 2;
            case "交付验收":
                return 3;
            case "形成收入":
                return 4;
            case "持续运维":
                return 5;
            case "挂起":
                return 11;
            case "丢标":
                return 12;
            default:
                return null;
        }
    }

    /**
     * 解析项目状态:true-1-公开;false-0-私密
     * @param status
     * @return
     */
    public String parseProgrammeStatus2(String status)
    {
        switch (status)
        {
            case "公开":
                return "1";
            case "私密":
                return "0";
            default:
                return null;
        }
    }

    public Boolean isTop(String isTop)
    {
        if (null != isTop && !"".equals(isTop))
        {
            switch (isTop)
            {
                case "是":
                    return true;
                case "否":
                    return false;
                default:
                    break;
            }
        }
        return null;
    }

    /**
     * 解析项目状态:true-1-公开;false-0-私密
     * @param trackStatusStr
     * @return
     */
    public Integer parseTrackStatusStr(String trackStatusStr)
    {
        switch (trackStatusStr)
        {
            case "进行中":
                return 1;
            case "关闭":
                return 2;
            case "挂起":
                return 3;
            default:
                return null;
        }
    }
}
